﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GroupEditModeBehavior.h"
#include "DbObjectUtils.h"
#include "IElementParentReporter.h"
#include "IEditMode.h"
#include "IGroup.h"
#include "IDocument.h"
#include "GroupElementChangeHandler.h"
#include "NdbUpgrade.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;



BEGIN_UPGRADE_CLASS(gcmp, GroupEditModeBehavior, 2)
ADD_NON_OBJECT_PROPERTY(Bool, IsStartEditing)
END_UPGRADE_CLASS


DBOBJECT_DATA_DEFINE(GroupEditModeBehavior)
{
    m_IsStartEditing = false;
}

GroupEditModeBehavior::~GroupEditModeBehavior(void)
{
}

IEditMode * GroupEditModeBehavior::Create(IDocument * pDoc)
{
    return IEditMode::Create(pDoc, NEW_AS_OWNER_PTR(GroupEditModeBehavior));
}

void GroupEditModeBehavior::SetListenStatus(bool isKeepListening)
{
    if (m_pElementChangeEventHandler)
    {
        m_pElementChangeEventHandler->SetListenStatus(isKeepListening);
    }
}

void GroupEditModeBehavior::StartToListenElementChanges(IDocument * pDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGroupEditMode != nullptr, L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");

    m_pElementChangeEventHandler = NEW_AS_OWNER_PTR(GroupElementChangeHandler, pGroupEditMode->GetEditingElementId());
    pDoc->AddElementsChangeEventHandler(ElementsChangeEventType::ElementsAdditionEvent, m_pElementChangeEventHandler.get());
    pDoc->AddElementsChangeEventHandler(ElementsChangeEventType::ElementsPostUpdationEvent, m_pElementChangeEventHandler.get());
    pDoc->AddElementsChangeEventHandler(ElementsChangeEventType::ElementsPreDeletionEvent, m_pElementChangeEventHandler.get());
}

void GroupEditModeBehavior::StopToListenElementChanges(IDocument * pDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    pDoc->DeleteElementsChangeEventHandler(ElementsChangeEventType::ElementsAdditionEvent, m_pElementChangeEventHandler.get());
    pDoc->DeleteElementsChangeEventHandler(ElementsChangeEventType::ElementsPostUpdationEvent, m_pElementChangeEventHandler.get());
    pDoc->DeleteElementsChangeEventHandler(ElementsChangeEventType::ElementsPreDeletionEvent, m_pElementChangeEventHandler.get());
    m_pElementChangeEventHandler = nullptr;
}

bool GroupEditModeBehavior::StartEditing(IDocument * pDoc, bool isCreating)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(nullptr != pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupEditMode != nullptr, L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");

    ElementId groupId = pGroupEditMode->GetEditingElementId();
    IGroup* pGroup = quick_cast<IGroup>(pDoc->GetElement(groupId));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroup, L"pGroup为空",L"GDMPLab",L"2024-03-30");

    pGroup->SetSubElementSnapble(true);

    StartToListenElementChanges(pDoc);

    SetIsStartEditing__(true);
    return true;
}

bool GroupEditModeBehavior::EndEditing(IDocument * pDoc)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(m_IsStartEditing, L"不在组编辑状态下",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    StopToListenElementChanges(pDoc);

    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupEditMode != nullptr, L"pBoxSelectMode为空",L"GDMPLab",L"2024-03-30");

    gcmp::IGroup* pGroup = quick_cast<gcmp::IGroup>(pDoc->GetElement(pGroupEditMode->GetEditingElementId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroup != nullptr, L"pGroup为空",L"GDMPLab",L"2024-03-30");
    pGroup->SetSubElementSnapble(false);

    SetIsStartEditing__(false);
    return true;
}

bool GroupEditModeBehavior::IsElementEditable(const IElement * pElement) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"传入指针pElement为空，不合法",L"GDMPLab",L"2024-03-30");
    IDocument * pDoc = pElement->GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupEditMode != nullptr,  L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");
    
    ElementId elemnetId = pElement->GetElementId();
    ElementId editingElementId = pGroupEditMode->GetEditingElementId();
    if (elemnetId == editingElementId)
        return true;

    const gcmp::IGroup* pGroup = quick_cast<const gcmp::IGroup>(pDoc->GetElement(editingElementId));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroup != nullptr, L"pGroup为空",L"GDMPLab",L"2024-03-30");

    return pGroup->IsElementInGroup(elemnetId);
}

void GroupEditModeBehavior::ReportParents(IDocument * pDoc, IElementParentReporter & reporter) const
{
    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGroupEditMode != nullptr, L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");
    if (pGroupEditMode->GetEditingElementId() != ElementId::InvalidID)
    {
        reporter.ReportWeak(pGroupEditMode->GetEditingElementId());
    }
}

void GroupEditModeBehavior::UpdateForWeakParentDeletion(IDocument * pDoc, const std::set<ElementId>& deletedElementIds)
{
    IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGroupEditMode != nullptr, L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");
    if (pGroupEditMode->GetEditingElementId() != ElementId::InvalidID && deletedElementIds.find(pGroupEditMode->GetEditingElementId()) != deletedElementIds.end())
    {
        DBG_WARN(L"不应该在EditMode有效时删除其中引用的Element",L"GDMPLab",L"2024-03-30");
    }
}
